iT邦幫忙

2021 iThome 鐵人賽

DAY 23
0

預編譯發生在何時?

執行全域前一刻,做全域的預編譯;執行function前一刻,做function的預編譯。


預編譯順序

  1. 宣告形參(形式參數)、
    宣告變數(就是指前面有var let const關鍵字,注意此時不賦值)
  2. 賦值實參(實際參數)給形參
  3. 宣告function(不管body,執行時才看)
  4. 開始執行(function變數這裡才賦值)

實戰gogo

console.log(fun(12,26,38))
console.log(fun(167,2))
console.log(`a=${a}`)
var a=1;
function fun(a,b,c,d){
	e=7;
	if(c){}else{c=0}
	return `a(${a}),b(${b}),c(${c}),d(${d})e(${e})`
}

console.log(`a=${a}`)

step1. 在全域執行前一刻,做全域預編譯

GO是global object 全局作用域

GO{
	
step1.1 宣告變數  舉例:看到 var a=1,定義a為全域變數,但不賦值
	a : undefined,

step1.2 宣告function 注意:宣告function時,不管他的body
	fun : function fun(a,b,c,d){......}
}

step2 全域預編譯結束,執行全域執行 - 看一行 執行一行

step2.1 看到console.log(fun(12,26,38)),執行fun function

console.log(fun(12,26,38))
function fun(a,b,c,d){
	e=7;
	if(c){}else{c=0}
	return `a(${a})+b(${b})+c(${c})+d(${d})`
}

step3 揪斗媽爹~~執行fun function的前一刻,做fun function區域預編譯

AO是activation object 局部作用域、活躍對象
為甚麼叫活躍對象,是因為function他在跑的時候,AO才存在,function結束,AO消失

step3.1 宣告形參

fun AO{
	a : undefined,
	b : undefined,
	c : undefined,
	d : undefined
}

宣告變數 沒有變數宣告
注意:e=7;前面沒有var let const關鍵字,不是需要宣告的變數

step3.2 賦值:實參給形參

fun AO{
	a : 12,
	b : 26,
	c : 38,
	d : undefined
}

step3.3 宣告function fun中沒有function需要宣告

step4 function區域預編譯結束,執行console.log(fun(12,26,38)) - 看一行 執行一行

step4.1 e=7; 變數的前面沒有 var let const,被判定為全域變數
小備註:因為已經在執行階段,所以變數不用先是undefined再變成7

GO{
	a : undefined,
	fun : function fun(a,b,c,d){......},
	e : 7
}

step4.2 執行完return,AO銷毀

step5 執行console.log(fun(167,2)) - 只講不一樣的

GO{
	a : undefined,
	fun : function fun(a,b,c,d){......},
	e : 7
}
fun AO{
	a : 167,
	b : 2,
	c : undefined,
	d : undefined
}

step5.1 if(c){}else{c=0}
因為undefinedfalsy,所以跳到else{c=0}

step5.2 fun執行完,AO銷毀

人肉編譯器們,剩下三行了,加油

step6 變數提升(hoisting)

console.log(`a=${a}`)
var a=1;
console.log(`a=${a}`)
GO{
	a : undefined,
	fun : function fun(a,b,c,d){......},
	e : 7
}

第一個console.log(a=${a})是在「預編譯後,賦值前」,所以a=undefined
第二個console.log(a=${a})是在「賦值後」,所以a=1


提升(Hoisting)

剛剛的「實戰gogo」,有看到變數的提升和function的提升。我們稍微總結一下 →

  • 變數的提升:undefined
    原因:取值時,發生在「預編譯後,賦值前」
    且因為變數是原始值
  • function的提升:完整的function(不是空殼function)
    原因:發生在「預編譯後,執行function時」,
    且因為function是引用值,會去參照function的body

但也不是所有function都會乖乖地提升,那到底是誰怎麼不乖呢?要拜乖乖?


資料來源

【JS深度指南】作用域、作用域链、预编译、闭包基础


上一篇
let宣告的全域變數,不再是全域屬性惹??
下一篇
在全域宣告的let
系列文
前端幼鳥三十天養成記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言